package com.hsgene.common.util.qiniu;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.hsgene.common.util.basic.JsonUtils;
import com.hsgene.common.util.bean.SpringApplicationContextUtil;
import com.hsgene.common.util.character.CharactersConstant;
import com.hsgene.common.util.redis.RedisConstants;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

/**
 * 七牛资源加签Serializer
 *
 * @author wangbing
 * @version 1.0, 2018/12/17
 */
public class QiniuResourceSerializer extends JsonSerializer<String> {

    // 图片Redis缓存键前缀
    public static final String IMAGE_REDIS_PREFIX = RedisConstants.DEFAULT_REDIS_PREFIX + RedisConstants.COLON_SPLIT + "image:";

    // 图片Redis缓存超时时间
    public static final long IMAGE_REDIS_EXPIRES = 50 * 60;

    private final static Logger LOGGER = LoggerFactory.getLogger(QiniuResourceSerializer.class);

    private RedisTemplate redisTemplate = (RedisTemplate) SpringApplicationContextUtil.getBean("redisTemplate");

    // 单张图片地址
    private static final int IMAGE_VALUE_TYPE_SINGLE = 1;

    // 以英文逗号分隔的多张图片
    private static final int IMAGE_VALUE_TYPE_MULTI = 2;

    // JSON字符串格式的多张图片
    private static final int IMAGE_VALUE_TYPE_JSON = 3;

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        /*if (StringUtils.isBlank(value)) {
            return;
        }*/
        if (null == value) {
            return;
        }
        if (StringUtils.isBlank(value)) {
            gen.writeString(value);
            return;
        }
        try {
            if (redisTemplate != null) {
                int valueType = checkValueType(value);
                if (IMAGE_VALUE_TYPE_SINGLE == valueType) {
                    gen.writeString(singleSign(value));
                } else if (IMAGE_VALUE_TYPE_MULTI == valueType) {
                    handleMultiAndJson(Stream.of(value.split(CharactersConstant.COMMA_EN)), gen);
                } else {
                    List<String> images = JsonUtils.jsonToObject(value, new TypeReference<List<String>>() {
                    });
                    if (!CollectionUtils.isEmpty(images)) {
                        handleMultiAndJson(images.stream(), gen);
                    }
                }
            } else {
                LOGGER.error("获取图片Redis缓存缓存失败，无法获得Bean->RedisTemplate");
                gen.writeString(QiniuCertificateUtil.getDownloadCertificateStr(value));
            }
        } catch (Exception e) {
            LOGGER.error("七牛资源签名异常：{}", value);
            LOGGER.error(e.getMessage(), e);
        }
    }

    private void handleMultiAndJson(Stream<String> stream, JsonGenerator gen) {
        stream.map(this::singleSign)
                .reduce((a, b) -> a + "," + b)
                .ifPresent(data -> {
                    try {
                        gen.writeString(data);
                    } catch (IOException e) {
                        LOGGER.error("七牛资源签名异常：{}", data);
                        e.printStackTrace();
                    }
                });
    }

    @SuppressWarnings("unchecked")
    private String singleSign(String value) {
        value = value.split("\\?")[0];
        String redisKey = IMAGE_REDIS_PREFIX + value.hashCode();
        String token = (String) redisTemplate.opsForValue().get(redisKey);
        String signUrl;
        if (StringUtils.isNotBlank(token)) {
            signUrl = value + "?" + token;
        } else {
            signUrl = QiniuCertificateUtil.getDownloadCertificateStr(value);
            if (StringUtils.isNotBlank(signUrl)) {
                String[] data = signUrl.split("\\?");
                if (data.length == 2) {
                    redisTemplate.opsForValue().set(redisKey, data[1], IMAGE_REDIS_EXPIRES, TimeUnit.SECONDS);
                }
            }
        }
        return signUrl;
    }


    private int checkValueType(String value) {
        if (value.contains("[")) {
            return IMAGE_VALUE_TYPE_JSON;
        } else if (value.split(CharactersConstant.COMMA_EN).length > 1) {
            return IMAGE_VALUE_TYPE_MULTI;
        } else {
            return IMAGE_VALUE_TYPE_SINGLE;
        }
    }
}
